package com.zkh.myutils.net.http;

import java.io.InputStream;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import com.zkh.myutils.code.Charsets;
import com.zkh.myutils.utils.StringUtils;

/**
 * http请求参数
 * @author zkh
 *
 */
public class RequestParam {
	
	//设置RequestProperty的属性名
	private static String[] requestProperties = {
		"User-Agent", "Accept", "Accept-Encoding", "Accept-Language", "Connection", "Content-Length",
		"Content-Type", "Referer", "Pragma", "Cache-Control", "Authorization", "Host", "Origin", "Cookie"
	};
	
	//请求地址
	private String url;
	//请求参数
	private String param;
	//请求方式
	private String method = "GET";
	//发送编码
	private Charset sendCode = Charsets.UTF_8;
	//接收编码
	private Charset receiveCode = Charsets.UTF_8;
	//响应类型
	private String responseContentType;
	//响应原始流
	private InputStream inputStream;
	//保存原始流，不处理文件
	private boolean saveAsStream;

	public RequestParam(String url) {
		this.url = url;
	}
	public RequestParam(String url, String param) {
		this.url = url;
		this.param = param;
	}
	public RequestParam(String url, String param, boolean isSendPost) {
		this.url = url;
		this.param = param;
		//POST请求
		if(isSendPost) {
			this.method = "POST";
		}
	}
	
	/**
	 * 设置请求属性
	 * @param connection 请求连接对象
	 */
	void setRequestProperty(URLConnection connection) {
		/** 组装特殊的属性值 **/
		//格式化cookie值
		String cookies = cookie;
		//存在sessionid
		if(StringUtils.isNotEmpty(sessionid)) {
			cookies = "JSESSIONID="+sessionid + (cookies==null ? "" : ("; " + cookies));
		}
		//内容长度
		String clength = contentLength==null ? null : contentLength.toString();
		//对应的属性值
		String[] values = {
			userAgent, accept, acceptEncoding, acceptLang, this.connection, clength,
			contentType, referer, pragma, cacheControl, authorization, host, origin, cookies
		};
		//属性数量
		int len = requestProperties.length;
		//遍历
		for(int i=0; i<len; i++) {
			//获取当前值
			String value = values[i];
			//有值
			if(value!=null) {
				connection.setRequestProperty(requestProperties[i], value);
			}
		}
		//超时时间
		if(connectTimeout>0) {
			connection.setConnectTimeout(connectTimeout);
		}
		if(readTimeout>0) {
			connection.setReadTimeout(readTimeout);
		}
	}
	
	public String getMethod() {
		return method;
	}
	/**
	 * 设置请求方式，可选值：get，post，不区分大小写。
	 * @param method
	 */
	public void setMethod(String method) {
		this.method = method;
	}
	public String getUrl() {
		return url;
	}
	/**
	 * 设置请求地址
	 * @param url
	 */
	public void setUrl(String url) {
		this.url = url;
	}
	public String getParam() {
		return param;
	}
	/**
	 * 设置参数。格式和浏览器传递参数相同。
	 * @param param
	 */
	public void setParam(String param) {
		this.param = param;
	}
	public Charset getSendCode() {
		return sendCode;
	}
	/**
	 * 设置发送编码，默认UTF-8
	 * @param sendCode
	 */
	public void setSendCode(Charset sendCode) {
		this.sendCode = sendCode;
	}
	public Charset getReceiveCode() {
		return receiveCode;
	}
	/**
	 * 设置接收编码，默认UTF-8
	 * @param receiveCode
	 */
	public void setReceiveCode(Charset receiveCode) {
		this.receiveCode = receiveCode;
	}
	
	/** 以下为RequestProperty属性设置，为null的属性会自动过滤 **/
	//Cookie
	private String cookie;
	//会话ID，如果存在该值，将发送一个JSESSIONID
	private String sessionid;
	//浏览器类型
	private String userAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)";
	//接收类型，默认任何类型均可
	private String accept = "*/*";
	//客户机支持的数据压缩格式
	private String acceptEncoding = "gzip, deflate";
	//浏览器所希望的语言各类，针对多语言版本使用
	private String acceptLang;
	//是否需要持久连接，默认值为持久连接
	private String connection = "Keep-Alive";
	//请求正文长度(byte)
	private Long contentLength;
	//请求的数据类型
	private String contentType;
	//当前发送请求的页面地址
	private String referer;
	//指定“no-cache”值表示服务器必须返回一个刷新后的文档
	private String pragma;
	//缓存控制
	private String cacheControl;
	//授权信息
	private String authorization;
	//访问主机名和端口
	private String host;
	//发送请求的主机名和端口
	private String origin;
	//读数据超时时间，大于0时生效，单位毫秒
	private int readTimeout;
	//连接超时时间，大于0时生效，单位毫秒
	private int connectTimeout;
	
	public String getCookie() {
		return cookie;
	}
	/**
	 * 设置Cookie，格式为: key=value(;key=value)*
	 * <br>如：setCookie("key=123;unique=456");
	 * @param cookie
	 */
	public void setCookie(String cookie) {
		this.cookie = cookie;
	}
	/**
	 * 设置Cookie，参数格式为：key<sub>1</sub>, value<sub>1</sub>, key<sub>2</sub>, value<sub>2</sub>, ···, key<sub>n</sub>, value<sub>n</sub><br/>
	 * 如：setCookie("key", "123", "unique", "456");
	 * <br><b>此处参数必须成对出现，奇数个参数，最后一个参数将自动忽略。</b>
	 * @param cookies Cookie参数，格式为：key<sub>1</sub>, value<sub>1</sub>, key<sub>2</sub>, value<sub>2</sub>, ···, key<sub>n</sub>, value<sub>n</sub>
	 */
	public void setCookies(String... cookies) {
		//参数组容器
		List<String> kvs = new ArrayList<String>();
		//遍历
		for(int i=0,len=cookies.length; i<len-1; i+=2) {
			kvs.add(cookies[i]+"="+cookies[i+1]);
		}
		this.cookie = String.join(";", kvs);
	}
	
	public String getSessionid() {
		return sessionid;
	}
	/**
	 * 设置sessionid
	 * @param sessionid
	 */
	public void setSessionid(String sessionid) {
		this.sessionid = sessionid;
	}
	public String getUserAgent() {
		return userAgent;
	}
	/**
	 * 设置浏览器信息，默认值为<b>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)</b>
	 * @param userAgent
	 */
	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}
	public String getAccept() {
		return accept;
	}
	/**
	 * 默认所有类型，可指定<b>JSON（application/json）</b>, <b>文本（text/plain）</b>格式等
	 * @param accept
	 */
	public void setAccept(String accept) {
		this.accept = accept;
	}
	public String getAcceptEncoding() {
		return acceptEncoding;
	}
	/**
	 * 设置客户机支持的数据压缩格式，默认“gzip, deflate”
	 * @param acceptEncoding
	 */
	public void setAcceptEncoding(String acceptEncoding) {
		this.acceptEncoding = acceptEncoding;
	}
	public String getAcceptLang() {
		return acceptLang;
	}
	/**
	 * 浏览器所希望的语言种类，针对多语言版本使用
	 * @param acceptLang
	 */
	public void setAcceptLang(String acceptLang) {
		this.acceptLang = acceptLang;
	}
	public String getConnection() {
		return connection;
	}
	/**
	 * 设置是否需要持久连接，默认值“Keep-Alive”
	 * @param connection
	 */
	public void setConnection(String connection) {
		this.connection = connection;
	}
	public Long getContentLength() {
		return contentLength;
	}
	/**
	 * 设置请求内容长度，单位：字节。
	 * @param contentLength
	 */
	public void setContentLength(Long contentLength) {
		this.contentLength = contentLength;
	}
	public String getContentType() {
		return contentType;
	}
	/**
	 * 请求的数据类型<br>
	 * 如发送JSON格式的值，可使用<b>application/json;charset=UTF-8</b>作为参数
	 * @param contentType
	 */
	public void setContentType(String contentType) {
		this.contentType = contentType;
	}
	public String getReferer() {
		return referer;
	}
	/**
	 * 设置当前发送请求的页面地址
	 * @param referer
	 */
	public void setReferer(String referer) {
		this.referer = referer;
	}
	public String getPragma() {
		return pragma;
	}
	/**
	 * 指定“no-cache”值表示服务器必须返回一个刷新后的文档，默认值为“no-cache”
	 * @param pragma
	 */
	public void setPragma(String pragma) {
		this.pragma = pragma;
	}
	public String getCacheControl() {
		return cacheControl;
	}
	/**
	 * 设置缓存控制
	 * @param cacheControl
	 */
	public void setCacheControl(String cacheControl) {
		this.cacheControl = cacheControl;
	}
	public String getAuthorization() {
		return authorization;
	}
	/**
	 * 设置授权信息，通常出现在对服务器发送的WWW-Authenticate头的应答中，一般用于保存Token
	 * @param authorization
	 */
	public void setAuthorization(String authorization) {
		this.authorization = authorization;
	}
	public String getHost() {
		return host;
	}
	/**
	 * 设置访问主机名和端口。格式：ip:port
	 * @param host
	 */
	public void setHost(String host) {
		this.host = host;
	}
	public String getOrigin() {
		return origin;
	}
	/**
	 * 设置发送请求的主机名和端口。格式：http(s)://ip.port
	 * @param origin
	 */
	public void setOrigin(String origin) {
		this.origin = origin;
	}
	/**
	 * 获取响应类型（请求后自动赋值）
	 * @return
	 */
	public String getResponseContentType() {
		return responseContentType;
	}
	public void setResponseContentType(String responseContentType) {
		this.responseContentType = responseContentType;
	}
	/**
	 * 获取请求原始响应流。只有调用setSaveAsStream方法设置为true时，才会有值
	 * @return
	 */
	public InputStream getInputStream() {
		return inputStream;
	}
	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}
	public boolean isSaveAsStream() {
		return saveAsStream;
	}
	/**
	 * 设置保存原始流。设置后原HttpUtils调用将返回null，通过RequestParam的getInputStream方法获取原始响应流
	 * @param saveAsStream
	 */
	public void setSaveAsStream(boolean saveAsStream) {
		this.saveAsStream = saveAsStream;
	}
	public int getReadTimeout() {
		return readTimeout;
	}
	/**
	 * 设置读取数据超时时间
	 * @param readTimeout 读取超时时间，单位毫秒
	 */
	public void setReadTimeout(int readTimeout) {
		this.readTimeout = readTimeout;
	}
	public int getConnectTimeout() {
		return connectTimeout;
	}
	/**
	 * 设置连接超时时间
	 * @param connectTimeout 连接超时时间，单位毫秒
	 */
	public void setConnectTimeout(int connectTimeout) {
		this.connectTimeout = connectTimeout;
	}
}
